import datetime
import re
import os
import shutil
import time

from kubernetes import client, config
from kubernetes.client import ApiException


def GetNamespace(name):
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    try:
        res = v1.read_namespace(name)
    except ApiException as e:
        res = None
    return res


def CreateNamespace(name):
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    body = {
        "apiVersion": "v1",
        "kind": "Namespace",
        "metadata": {
            "name": name,
        }
    }
    ret = v1.create_namespace(body=body)
    return ret


def DeleteNamespace(name):
    if GetNamespace(name) is None:
        return
    CpPodToLocal(name)
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    ret = v1.delete_namespace(name)
    return ret


def CreateDeploy(namespace, name, image):
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.AppsV1Api()
    body = {
        "apiVersion": "apps/v1",
        "kind": "Deployment",
        "metadata": {
            "name": name + "-app"
        },
        "spec": {
            "selector": {
                "matchLabels": {
                    "app": name
                }
            },
            "replicas": 1,
            "template": {
                "metadata": {
                    "labels": {
                        "app": name
                    }
                },
                "spec": {
                    "containers": [
                        {
                            "name": "pytorch",
                            "image": image,
                            "imagePullPolicy": "IfNotPresent",
                            "ports": [
                                {
                                    "containerPort": 8888
                                }, {
                                    "containerPort": 6006
                                }
                            ]
                        }
                    ]
                }
            }
        }
    }
    try:
        res = v1.create_namespaced_deployment(body=body, namespace=namespace)
    except ApiException as e:
        res = e
        print(e)
    return res


def CreateService(namespace, name):
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    body = {
        "apiVersion": "v1",
        "kind": "Service",
        "metadata": {
            "name": "svc-" + name,
        },
        "spec": {
            "ports": [
                {
                    "name": "jupyter",
                    "port": 9000,
                    "protocol": "TCP",
                    "targetPort": 8888,
                }, {
                    "name": "tensorboard",
                    "port": 9001,
                    "protocol": "TCP",
                    "targetPort": 6006,
                }
            ],
            "selector": {
                "app": name
            },
            "type": "NodePort"
        }
    }
    try:
        res = v1.create_namespaced_service(body=body, namespace=namespace)
    except ApiException as e:
        res = e
        print(e)
    return res


def GetToken(namespace, name):
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    while True:
        try:
            podname = v1.list_namespaced_pod(namespace).items[0].metadata.name
            log = v1.read_namespaced_pod_log(podname, namespace)
            token = re.findall(r"token=(.+?)\n", log)[0]
            ports = v1.read_namespaced_service("svc-" + name, namespace).spec.ports
            port_jupyter = ports[0].node_port
            port_tensorboard = ports[1].node_port
        except Exception:
            time.sleep(1)
            continue
        f = getIpynb(namespace)

        jupyter_str = str(port_jupyter)
        if f is not None:
            f = f.replace("/root/data/"+namespace+"/data/","")
            jupyter_str += "/lab/tree/" + f
        jupyter_str += "/?token=" + token
        return {"jupyter": jupyter_str, "tensorboard": str(port_tensorboard)}


def GetLastTime(namespace, name):
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    pods = v1.list_namespaced_pod(namespace)

    try:
        podname = pods.items[0].metadata.name
    except Exception:
        return None
    log = v1.read_namespaced_pod_log(podname, namespace)
    res = re.findall(r"202[0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]", log)
    res = res[len(res) - 1]
    res = datetime.datetime.strptime(res, "%Y-%m-%d %H:%M:%S.%f")
    return res


def CpPodToLocal(namespace):
    if GetNamespace(namespace) is None:
        return
    namespace = str(namespace)
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    podname = v1.list_namespaced_pod(namespace).items[0].metadata.name
    if os.path.exists("/root/data/" + namespace):
        shutil.rmtree("/root/data/" + namespace)
    if not os.path.exists(localpath(namespace)):
        os.system("mkdir -p " + localpath(namespace))

    cmd = "kubectl -n " + namespace + " cp " + podname + ":/root/data " + localpath(namespace)
    print(cmd)
    print(os.system(cmd))


def CpLocalToPod(namespace):
    if not os.path.exists(localpath(namespace)):
        return
    if not os.listdir(localpath(namespace)):
        return
    config.kube_config.load_kube_config(config_file="/etc/kubernetes/admin.conf")
    v1 = client.CoreV1Api()
    podname = v1.list_namespaced_pod(namespace).items[0].metadata.name
    cmd = "kubectl -n " + namespace + " cp " + localpath(namespace) + " " + podname + ":/root/"
    cnt = 0
    while True:
        cnt += 1
        if cnt >= 60:
            break
        print(cmd)
        res = os.system(cmd)
        print(res)
        if res == 0:
            break
        else:
            time.sleep(1)


def getIpynb(id):
    path = localpath(id)

    if os.path.exists("/usr/local/nginx/html/data/" + str(id)):
        shutil.rmtree("/usr/local/nginx/html/data/" + str(id))

    f = None
    if os.path.exists(path + 'README.ipynb'):
        f = path + 'README.ipynb'
    else:
        if os.path.exists(path):
            for filename in os.listdir(path):
                if filename.endswith(".ipynb"):
                    f = path + filename
                    break
    return f


def localpath(namespace):
    return "/root/data/" + namespace + "/data/"
